home *** CD-ROM | disk | FTP | other *** search
/ Delphi 5 for Professionals / DELPHI5.iso / AddOns / Components / TEECHART / Src Code / TEESTORE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-24  |  12.5 KB  |  447 lines

  1. {*********************************************}
  2. {  TeeChart Storage functions                 }
  3. {  Copyright (c) 1997-98 by David Berneda     }
  4. {  All rights reserved                        }
  5. {*********************************************}
  6. {$I teedefs.inc}
  7. unit TeeStore;
  8.  
  9. interface
  10.  
  11. Uses Classes, Teengine, Chart;
  12.  
  13. { Read a Chart from a file ( Chart1,'c:\demo.tee' ) }
  14. Procedure LoadChartFromFile(Var AChart:TCustomChart; Const AName:String);
  15.  
  16. { Write a Chart to a file ( Chart1,'c:\demo.tee' ) }
  17. Procedure SaveChartToFile(AChart:TCustomChart; Const AName:String);
  18.  
  19. { The same using TStream components (good for BLOB fields, etc)  }
  20. Procedure LoadChartFromStream(Var AChart:TCustomChart; AStream:TStream);
  21. Procedure SaveChartToStream(AChart:TCustomChart; AStream:TStream);
  22.  
  23. { (Advanced) Read charts and check for errors  }
  24. { return True if ok, False to stop loading }
  25. type TProcTeeCheckError=function(const Message: string): Boolean of object;
  26.  
  27. Procedure LoadChartFromStreamCheck( Var AChart:TCustomChart;
  28.                                     AStream:TStream;
  29.                                     ACheckError:TProcTeeCheckError
  30.                                );
  31.  
  32. Procedure LoadChartFromFileCheck( Var AChart:TCustomChart;
  33.                                   Const AName:String;
  34.                                   ACheckError:TProcTeeCheckError
  35.                                   );
  36.  
  37. { Returns if a Series has "X" values }
  38. Function HasNoMandatoryValues(ASeries:TChartSeries):Boolean;
  39.  
  40. { returns the "no mandatory" values of ASeries ( usually XValues ) }
  41. Function NotMandatoryList(ASeries:TChartSeries):TChartValueList;
  42.  
  43. { Convert a *.tee file to text format, without point values }
  44. Procedure ConvertTeeFileToText(Const InputFile,OutputFile:String);
  45.  
  46. implementation
  47.  
  48. Uses Graphics, SysUtils, TeeProcs, TeCanvas;
  49.  
  50. Const MagicTeeFile  =$3060;
  51.       {$IFDEF D4}
  52.       VersionTeeFile=$0120; { Delphi 4 }
  53.       {$ELSE}
  54.       {$IFDEF C3}
  55.       VersionTeeFile=$0110; { C++ Builder 3 }
  56.       {$ELSE}
  57.       {$IFDEF D3}
  58.       VersionTeeFile=$0100; { Delphi 3 }
  59.       {$ELSE}
  60.       {$IFDEF D2}
  61.       VersionTeeFile=$0090; { Delphi 2 }
  62.       {$ELSE}
  63.       {$IFDEF D1}
  64.       VersionTeeFile=$0080; { Delphi 1 }
  65.       {$ELSE}
  66.       VersionTeeFile=$0099; { C++ Builder 1 }
  67.       {$ENDIF}
  68.       {$ENDIF}
  69.       {$ENDIF}
  70.       {$ENDIF}
  71.       {$ENDIF}
  72.  
  73.  
  74. Type TTeeFileHeader=packed record
  75.          Magic   : Word; { secure checking }
  76.          Version : Word; { Chart file version }
  77.      end;
  78.  
  79.      TeeFormatFlags=(tfNoMandatory,tfColor,tfLabel);
  80.      TeeFormatFlag =set of TeeFormatFlags;
  81.  
  82. Procedure ReadSeriesData(AStream:TStream; ASeries:TChartSeries);
  83.  
  84.   Function ReadLabel:String;
  85.   Var L:Byte;
  86.   begin
  87.     L := 0;
  88.     { read the label length }
  89.     AStream.Read(L, SizeOf(L));
  90.     { read the label contents }
  91.     {$IFDEF D1}
  92.     Result[0]:=Char(L);
  93.     AStream.Read(Pointer(@Result[1])^, L);
  94.     {$ELSE}
  95.     SetString(Result, PChar(nil), L);
  96.     AStream.Read(Pointer(Result)^, L);
  97.     {$ENDIF}
  98.   end;
  99.  
  100. Var tmpFormat:TeeFormatFlag;
  101.  
  102.   Procedure ReadSeriesPoint(Index:Longint);
  103.   Var tmpFloat : Double;
  104.       Ax       : Double;
  105.       Ay       : Double;
  106.       AColor   : TColor;
  107.       ALabel   : String;
  108.       tmpIndex : Longint;
  109.       tt       : Longint;
  110.   begin
  111.     { read the "X" value if exists }
  112.     if tfNoMandatory in tmpFormat then AStream.Read(AX,Sizeof(AX));
  113.     { read the "Y" value }
  114.     AStream.Read(AY,Sizeof(AY));
  115.     { read the Color value if exists }
  116.     if tfColor in tmpFormat then AStream.Read(AColor,Sizeof(AColor))
  117.                             else AColor:=clTeeColor;
  118.     { read the Label value if exists }
  119.     if tfLabel in tmpFormat then ALabel:=ReadLabel
  120.                             else ALabel:='';
  121.  
  122.     With ASeries do
  123.     begin
  124.       { read the rest of lists values }
  125.       for tt:=2 to ValuesLists.Count-1 do
  126.       begin
  127.         AStream.Read(tmpFloat,SizeOf(tmpFloat));
  128.         ValuesLists.ValueList[tt].TempValue:=tmpFloat;
  129.       end;
  130.       { add the new point }
  131.       if tfNoMandatory in tmpFormat then
  132.          tmpIndex:=AddXY(AX,AY,ALabel,AColor)
  133.       else
  134.          tmpIndex:=Add(AY,ALabel,AColor);
  135.       { finish adding the point with the rest of lists values }
  136.       AddValue(tmpIndex);
  137.     end;
  138.   end;
  139.  
  140. Var tmpCount : Longint;
  141.     t        : Longint;
  142. begin
  143.   { empty the Series }
  144.   ASeries.Clear;
  145.   { read the point flags }
  146.   AStream.Read(tmpFormat,SizeOf(tmpFormat));
  147.   { read the number of points }
  148.   AStream.Read(tmpCount,Sizeof(tmpCount));
  149.   { read each point }
  150.   for t:=0 to tmpCount-1 do ReadSeriesPoint(t);
  151. end;
  152.  
  153. Procedure ReadChartData(AStream:TStream; AChart:TCustomChart);
  154. Var t : Longint;
  155. begin { read each Series data }
  156.   for t:=0 to AChart.SeriesCount-1 do ReadSeriesData(AStream,AChart[t]);
  157. end;
  158.  
  159. { Special reader to skip Delphi 3 or 4 new properties when
  160.   reading Charts in Delphi 1.0 or 2.0 }
  161. type TChartReader=class(TReader)
  162.      protected
  163.        function Error(const Message: string): Boolean; override;
  164.      public
  165.        CheckError:TProcTeeCheckError;
  166.      end;
  167.  
  168. function TChartReader.Error(const Message: string): Boolean;
  169. begin
  170.   if Assigned(CheckError) then result:=CheckError(Message)
  171.                           else result:=True;
  172. end;
  173.  
  174. { Reads Series and Points from a Stream into a Chart }
  175. Procedure LoadChartFromStreamCheck( Var AChart:TCustomChart;
  176.                                     AStream:TStream;
  177.                                     ACheckError:TProcTeeCheckError);
  178. Var Header : TTeeFileHeader;
  179.     t      : Longint;
  180.     Reader : TChartReader;
  181. begin
  182.   {$IFDEF TEETRIAL}
  183.   TeeTrial(AChart.ComponentState);
  184.   {$ENDIF}
  185.   { read file header }
  186.   AStream.Read(Header,SizeOf(Header));
  187.   { check is a valid Tee file }
  188.   if Header.Magic=MagicTeeFile then
  189.   begin
  190.     { remove all child Series }
  191.     AChart.FreeAllSeries;
  192.     { read the Chart and Series properties }
  193.     Reader := TChartReader.Create(AStream, 4096);
  194.     try
  195.       Reader.CheckError:=ACheckError;
  196.       Reader.ReadRootComponent(AChart);
  197.     finally
  198.       Reader.Free;
  199.     end;
  200.     if Assigned(AChart) then
  201.     begin
  202.       { read the Series points }
  203.       ReadChartData(AStream,AChart);
  204.       { change each Series ownership }
  205.       if AChart.Owner<>nil then
  206.       for t:=0 to AChart.SeriesCount-1 do
  207.       begin
  208.         AChart[t].Owner.RemoveComponent(AChart[t]);
  209.         AChart.Owner.InsertComponent(AChart[t]);
  210.       end;
  211.     end
  212.     else raise Exception.Create('Invalid Chart in *.TEE file');
  213.   end
  214.   else raise Exception.Create('Wrong *.TEE file format');
  215. end;
  216.  
  217. Procedure LoadChartFromStream(Var AChart:TCustomChart; AStream:TStream);
  218. begin
  219.   LoadChartFromStreamCheck(AChart,AStream,nil);
  220. end;
  221.  
  222. Procedure LoadChartFromFileCheck( Var AChart:TCustomChart;
  223.                                   Const AName:String;
  224.                                   ACheckError:TProcTeeCheckError );
  225. Var tmp:TFileStream;
  226. begin
  227.   tmp:=TFileStream.Create(AName,fmOpenRead);
  228.   try
  229.     LoadChartFromStreamCheck(AChart,tmp,ACheckError);
  230.   finally
  231.     tmp.Free;
  232.   end;
  233. end;
  234.  
  235. Procedure LoadChartFromFile(Var AChart:TCustomChart; Const AName:String);
  236. begin
  237.   LoadChartFromFileCheck(AChart,AName,nil);
  238. end;
  239.  
  240. { Create a text file from a binary *.tee file }
  241. Procedure ConvertTeeFileToText(Const InputFile,OutputFile:String);
  242. var SInput  : TFileStream;
  243.     SOutput : TFileStream;
  244.     Header  : TTeeFileHeader;
  245. begin
  246.   SInput:=TFileStream.Create(InputFile,fmOpenRead);
  247.   try
  248.     { read file header }
  249.     SInput.Read(Header,SizeOf(Header));
  250.     { check is a valid Tee file }
  251.     if Header.Magic=MagicTeeFile then
  252.     begin
  253.       SOutput:=TFileStream.Create(OutputFile,fmCreate);
  254.       try
  255.         ObjectBinaryToText(SInput,SOutput);
  256.       finally
  257.         SOutput.Free;
  258.       end;
  259.     end;
  260.   finally
  261.     SInput.Free;
  262.   end;
  263. end;
  264.  
  265. { Returns if a Series has "X" values (or Y values for HorizBar series) }
  266. Function HasNoMandatoryValues(ASeries:TChartSeries):Boolean;
  267. var t        : Longint;
  268.     tmpCount : Longint;
  269.     tmp      : TChartValueList;
  270. begin
  271.   result:=False;
  272.   With ASeries do
  273.   if Count>0 then
  274.   begin
  275.     tmp:=NotMandatoryList(ASeries);
  276.     if (tmp.First=0) and (tmp.Last=Count-1) then
  277.     begin
  278.       tmpCount:=MinLong(10000,Count-1);
  279.       for t:=0 to tmpCount do
  280.       if tmp[t]<>t then
  281.       begin
  282.         result:=True;
  283.         Exit;
  284.       end;
  285.     end
  286.     else result:=True;
  287.   end;
  288. end;
  289.  
  290. { Returns if a Series has Colors }
  291. Function HasColors(ASeries:TChartSeries):Boolean;
  292. var t        : Longint;
  293.     tmpCount : Longint;
  294.     tmpColor : TColor;
  295.     tmpSeriesColor:TColor;
  296. begin
  297.   result:=False;
  298.   With ASeries do
  299.   begin
  300.     tmpSeriesColor:=SeriesColor;
  301.     tmpCount:=MinLong(10000,Count-1);
  302.     for t:=0 to tmpCount do
  303.     begin
  304.       tmpColor:=ValueColor[t];
  305.       if (tmpColor<>clTeeColor) and
  306.          (tmpColor<>tmpSeriesColor) then
  307.       begin
  308.         result:=True;
  309.         exit;
  310.       end;
  311.     end;
  312.   end;
  313. end;
  314.  
  315. { Returns if a Series has labels }
  316. Function HasLabels(ASeries:TChartSeries):Boolean;
  317. var t        : Longint;
  318.     tmpCount : Longint;
  319. begin
  320.   result:=False;
  321.   tmpCount:=MinLong(10000,ASeries.Count-1);
  322.   for t:=0 to tmpCount do
  323.   if ASeries.XLabel[t]<>'' then
  324.   begin
  325.     result:=True;
  326.     exit;
  327.   end;
  328. end;
  329.  
  330. { Determine what a Series point is made of }
  331. Function SeriesGuessContents(ASeries:TChartSeries):TeeFormatFlag;
  332. begin
  333.   if HasNoMandatoryValues(ASeries) then result:=[tfNoMandatory]
  334.                                    else result:=[];
  335.   if HasColors(ASeries) then result:=result+[tfColor];
  336.   if HasLabels(ASeries) then result:=result+[tfLabel];
  337. end;
  338.  
  339. Procedure WriteSeriesData(AStream:TStream; ASeries:TChartSeries);
  340.  
  341.   Procedure WriteLabel(Const AString:String);
  342.   Var L:Byte;
  343.   begin
  344.     L:=Length(AString);
  345.     AStream.Write(L,SizeOf(L));
  346.     {$IFDEF D1}
  347.     AStream.Write((@AString[1])^,L);
  348.     {$ELSE}
  349.     AStream.Write(PChar(AString)^,L);
  350.     {$ENDIF}
  351.   end;
  352.  
  353. Var tmpFormat      : TeeFormatFlag;
  354.     tmpNoMandatory : TChartValueList;
  355.  
  356.   Procedure WriteSeriesPoint(Index:Longint);
  357.   Var tmpFloat : Double;
  358.       tmpColor : TColor;
  359.       tt       : Longint;
  360.   begin
  361.     { write the "X" point value, if exists }
  362.     if tfNoMandatory in tmpFormat then
  363.     begin
  364.       tmpFloat:=tmpNoMandatory[Index];
  365.       AStream.Write(tmpFloat,Sizeof(tmpFloat));
  366.     end;
  367.     { write the "Y" point value }
  368.     tmpFloat:=ASeries.MandatoryValueList[Index];
  369.     AStream.Write(tmpFloat,Sizeof(tmpFloat));
  370.  
  371.     { write the Color point value, if exists }
  372.     if tfColor in tmpFormat then
  373.     begin
  374.       tmpColor:=ASeries.ValueColor[Index];
  375.       AStream.Write(tmpColor,Sizeof(tmpColor));
  376.     end;
  377.     { write the Label point value, if exists }
  378.     if tfLabel in tmpFormat then WriteLabel(ASeries.XLabel[Index]);
  379.     { write the rest of values (always) }
  380.     for tt:=2 to ASeries.ValuesLists.Count-1 do
  381.     begin
  382.       tmpFloat:=ASeries.ValuesLists.ValueList[tt][Index];
  383.       AStream.Write(tmpFloat,SizeOf(tmpFloat));
  384.     end;
  385.   end;
  386.  
  387. var t   : Longint;
  388.     tmp : Longint;
  389. begin
  390.   { write the "flag" containing the format of a point }
  391.   tmpFormat:=SeriesGuessContents(ASeries);
  392.   AStream.Write(tmpFormat,SizeOf(tmpFormat));
  393.   { write all points. pre-calculate tmpNoMandatory }
  394.   tmpNoMandatory:=NotMandatoryList(ASeries);
  395.   { write the number of points }
  396.   tmp:=ASeries.Count;
  397.   AStream.Write(tmp,Sizeof(tmp));
  398.   for t:=0 to tmp-1 do WriteSeriesPoint(t);
  399. end;
  400.  
  401. Procedure WriteChartData(AStream:TStream; AChart:TCustomChart);
  402. Var t : Longint;
  403. begin
  404.   for t:=0 to AChart.SeriesCount-1 do WriteSeriesData(AStream,AChart[t]);
  405. end;
  406.  
  407. Procedure SaveChartToStream(AChart:TCustomChart; AStream:TStream);
  408. var Header : TTeeFileHeader;
  409. begin
  410.   {$IFDEF TEETRIAL}
  411.   TeeTrial(AChart.ComponentState);
  412.   {$ENDIF}
  413.   { write file header, with "magic" number and version }
  414.   Header.Magic:=MagicTeeFile;
  415.   Header.Version:=VersionTeeFile;
  416.   AStream.Write(Header,SizeOf(Header));
  417.   { write the Chart and Series properties }
  418.   AStream.WriteComponent(AChart);
  419.   { write the Series points }
  420.   WriteChartData(AStream,AChart);
  421. end;
  422.  
  423. Procedure SaveChartToFile(AChart:TCustomChart; Const AName:String);
  424. Var tmp : TFileStream;
  425. begin
  426.   tmp:=TFileStream.Create(AName,fmCreate);
  427.   try
  428.     SaveChartToStream(AChart,tmp);
  429.   finally
  430.     tmp.Free;
  431.   end;
  432. end;
  433.  
  434. Function NotMandatoryList(ASeries:TChartSeries):TChartValueList;
  435. begin
  436.   With ASeries do if YMandatory then result:=XValues else result:=YValues;
  437. end;
  438.  
  439. {$IFNDEF TEEOCX}
  440. type TODBCChart=class(TChart)
  441.      end;
  442.  
  443. initialization
  444.   RegisterClass(TODBCChart);
  445. {$ENDIF}
  446. end.
  447.